﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity.SqlServer;
using System.Data.Entity.Core.Objects;
using System.Web.UI.WebControls;
using GrayParrot.Core.Filters;

namespace GrayParrot.Web.Controls
{
    internal static class ColumnSearchIndex
    {
        static int m_index = 0;

        public static void Initialize(int start)
        {
            m_index = start;
        }

        public static int Start
        {
            get
            {
                int retValue = 0;

                if (m_index == 0 || m_index == 1)
                    retValue = m_index;
                else
                    throw new Exception(string.Format("ColumnSearchIndex Start value not set correctly. It can be 0 or 1. Actual value: {0}", m_index));

                return retValue;
            }
        }

        public static int Next
        {
            get { return m_index++; }
        }

        internal static void Increment()
        {
            m_index++;
        }

        internal static int Get
        {
            get { return m_index; }
        }
    }

    public abstract class ResultSet<T> where T : class
    {
        protected DTParameters Param { set; get; }
        private Expression<Func<T, bool>> m_whereClausole = PredicateBuilder.True<T>();

        private List<String> m_columnSearch = null;

        public IQueryable<T> Data { set; get; }
        public int Count { internal set; get; }
        public int ColumnIndex
        {
            get
            {
                if ((ColumnSearchIndex.Get == 0) || (ColumnSearchIndex.Get == 1))
                {
                    int retValue = ColumnSearchIndex.Start;
                    ColumnSearchIndex.Increment();
                    return retValue;
                }
                else
                {
                    return ColumnSearchIndex.Next;
                }
            }
        }

        public ResultSet(DTParameters param, IQueryable<T> result)
        {
            Param = param;

            if (result != null)
            {
                Data = result;
                Count = result.Count();

                m_columnSearch = new List<string>();

                foreach (var col in param.Columns)
                {
                    m_columnSearch.Add(col.Search.Value);
                }

                if (m_columnSearch.Count() > 0)
                {
                    ColumnSearchIndex.Initialize(this.Param.SelectionMode == SelectionModes.Single ? 0 : 1);
                }
            }
            else
            {
                Data = new List<T>(0).AsQueryable<T>();
            }
        }

        public virtual Expression<Func<T, bool>> ApplyGeneralFilter(string searchPattern) { return m_whereClausole; }
        public virtual Expression<Func<T, bool>> ApplyGeneralColumnsFilter(List<String> columnSearch) { return m_whereClausole; }

        /// <summary>
        /// Gets the search element in the zero-based search element list...
        /// </summary>
        /// <param name="elementPosition">The element position.</param>
        /// <returns></returns>
        public string GetElement(int elementPosition)
        {
            string retValue = string.Empty;

            int m_stepForMulti = (this.Param.SelectionMode == SelectionModes.Single ? 0 : 1);

            retValue = m_columnSearch[elementPosition + m_stepForMulti];

            return retValue;
        }

        public DTResult<T> GetResult()
        {
            DTResult<T> retValue = new DTResult<T>();

            if (Param.Search.Value != null)
            {
                m_whereClausole = ApplyGeneralFilter(Param.Search.Value);
            }
            else
            {
                if ((m_columnSearch != null) && (m_columnSearch.Any(x => x != null)))
                {
                    m_whereClausole = ApplyGeneralColumnsFilter(m_columnSearch);
                }
            }

            if (Data.Count() == 0)
            {
                retValue.draw = Param.Draw;
                retValue.data = Data.ToList();
                retValue.recordsFiltered = 0;
                retValue.recordsTotal = 0;
            }
            else
            {
                retValue.draw = Param.Draw;
                if (Param.Length != -1)
                {
                    retValue.data = Data.Where(m_whereClausole).SortBy(Param.SortOrder).Skip(Param.Start).Take(Param.Length).ToList();
                }
                else
                {
                    retValue.data = Data.Where(m_whereClausole).SortBy(Param.SortOrder).ToList();
                }
                retValue.recordsFiltered = Data.Where(m_whereClausole).Count();
                retValue.recordsTotal = Data.Where(m_whereClausole).Count();
            }

            //
            return retValue;
        }
    }
}
